/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.port;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;
import org.xptracker.domain.*;
import org.xptracker.persistence.PersistenceManager;

import java.io.InputStream;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;


public class XPlannerImporter {

  public static void importData(InputStream stream, PersistenceManager.UpdateReceiver receiver, Domain domain, User defaultUser) {
    List<Iteration> iterations = new LinkedList<Iteration>();
    SAXReader reader = new SAXReader();
    Document document = null;
    try {
      document = reader.read(stream);
    } catch (DocumentException e) {
      throw new RuntimeException("Error reading document", e);
    }
    for(Object iteration : document.selectNodes("/xplanner/iterations/iteration")) {
      DefaultElement e = (DefaultElement) iteration;
      iterations.add(new Iteration(e));
    }
    for(Iteration iteration : iterations) {
      for(StoryData storyData : iteration.stories) {
        Story story = new Story();

        if(storyData.completed) {
          story.setCompletedDate(new Date());
          story.setState(State.developed);
        }
        if(StringUtils.isNotBlank(storyData.customer)) {
          Customer customer = domain.loadCustomer(storyData.customer);
          if(customer == null) {
            customer = new Customer(storyData.customer);
            receiver.insert(customer);
          }
          story.addCustomer(customer);
        }
        story.setSeverity(storyData.getSeverity());
        story.setDescription("Imported from XPlanner Story " + storyData.id + "\n\n" + storyData.description);
        story.setSummary(storyData.name);
        story.setEstimate(storyData.estimatedHours);
        story.setCreator(defaultUser);
        //todo do something with priority
        for(TaskData taskData : storyData.tasks) {
          StoryTask task = new StoryTask();
          if(taskData.completed) {
            task.setCompletedDate(new Date());
            task.setComplete(true);
          }
          task.setDescription(taskData.description);
          task.setSummary(taskData.name);
          task.setOwner(defaultUser);
          story.getTasks().add(task);
          receiver.insert(task);
        }
        receiver.insert(story);
      }
    }
  }


  public static void main(String[] args) throws Exception {


  }

  private static String getText(Node element,  String pathOrName)  {
    return ((DefaultElement) element.selectNodes(pathOrName).iterator().next()).getTextTrim();
  }

  private static Double getDouble(DefaultElement element,  String pathOrName) {
    return Double.valueOf(getText(element, pathOrName));
  }

  private static Integer getInteger(DefaultElement element,  String pathOrName) {
    return Integer.valueOf(getText(element, pathOrName));
  }


  private static class Iteration {
    List<StoryData> stories = new LinkedList<StoryData>();
    String name;
    Integer id;
    public Iteration(DefaultElement element ) {
      this.id = getInteger(element, "id");
      this.name = getText(element, "name");
      parseStories(element);
    }

    private void parseStories(Node element) {
      List stories = element.selectNodes("userStories/userStory");
      for(Object storyObj : stories) {
        DefaultElement story = (DefaultElement) storyObj;
        Integer iterId = getInteger(story, "iterationId");
        if(iterId.equals(this.id)) {
          this.stories.add(new StoryData(story));
        } else {
          System.out.println("Not my child");
        }
      }
    }

    public String toString() {
      StringBuilder builder = new StringBuilder();
      builder.append(this.name).append("\n");
      for(StoryData s : stories) {
        builder.append("\t").append(s.toString()).append("\n");
      }
      return builder.toString();
    }
  }

  private static class StoryData {
    double actualHours;
    double estimatedHours;
    int priority;
    boolean completed;
    int id;
    String description;
    String name;
    String customer;
    List<TaskData> tasks = new LinkedList<TaskData>();

    public StoryData(DefaultElement story) {
       this.actualHours = getDouble(story, "actualHours");
      this.estimatedHours = getDouble(story, "estimatedHours");
      this.id= getInteger(story, "id");
      this.priority= getInteger(story, "priority");
      this.description = getText(story, "description");
      this.completed = Boolean.valueOf(getText(story, "completed"));
      this.name = getText(story, "name");
      try {
        this.customer = getText(story, "customer//name");
      } catch (NoSuchElementException e) {
        LogFactory.getLog(getClass()).warn("No customer for story with id " + id);
      }
      parseTasks(story);
    }

    private void parseTasks(DefaultElement element) {
      List tasks = element.selectNodes("tasks/task");
      for(Object taskObj : tasks) {
        DefaultElement task = (DefaultElement) taskObj;
        Integer storyId = getInteger(task, "story");
        if(storyId.equals(this.id)) {
          this.tasks.add(new TaskData(task));
        }
      }
    }

    public String toString() {
      StringBuilder builder = new StringBuilder();
      builder.append(this.id).append(" ").append(this.description).append(" actual: ").append(this.actualHours).append(" estimated:").append(this.estimatedHours).append(" priority:").append(this.priority).append(" completed:").append(this.completed).append(" customer: ").append(this.customer);
      builder.append("\n\tTasks: ");
      for(TaskData t : tasks) {
        builder.append("\t").append(t).append("\n");
      }
      return builder.toString();
    }

    public Severity getSeverity() {
      switch (priority) {
        case 0: return Severity.scorcher;
        case 1: return Severity.hot;
        case 2: return Severity.warm;
        case 3: return Severity.tepid;
        case 4: return Severity.tepid;
        default:return Severity.cold;
      }
    }
  }

  private static class TaskData {
    boolean completed;
    String description;
    String name;

    public TaskData(DefaultElement element) {
      this.completed = Boolean.valueOf(getText(element, "completed"));
      this.description = getText(element, "description");
      this.name = getText(element, "name");
    }

    public String toString() {
      return this.description + " completed:" + completed;
    }
  }

}


